﻿using JetBrains.Annotations;

namespace Rsdn.Janus
{
    using System;
    using System.Text.RegularExpressions;
    using Rsdn.Framework.Formatting;

    public static class UrlHelper
    {
        /// <summary>
        /// Проверяем присутствует ли в заданном адресе имя домена
        /// </summary>
        /// <param name="urlMatch">Результаты предварительноцй проверки URL.</param>
        /// <param name="urlAddress">Проверяемый URL адрес.</param>
        /// <returns>
        ///     <c>true</c> если имя домена присутствует; иначе, <c>false</c>.
        /// </returns>
        // Данная функция видится "неустойчивой". Лучше убрать чем укономить время дополнительного разбора.
        //public static bool IsDomainPresent(Match urlMatch, string urlAddress)
        //{
        //    string testUri = urlAddress;
        //    if (!IsSchemePresent(urlMatch))
        //    {
        //        testUri = "http://" + testUri;
        //    }

        //    bool ret = IsDomainPresentInternal(testUri);

        //    return ret;
        //}

        /// <summary>
        /// Проверяем присутствует ли в заданном адресе имя домена
        /// </summary>
        /// <param name="urlAddress">Проверяемый URL адрес.</param>
        /// <returns>
        ///     <c>true</c> если имя домена присутствует; иначе, <c>false</c>.
        /// </returns>
        public static bool IsDomainPresent(string urlAddress)
        {
            string testUri = urlAddress;

            testUri = AddUrlScheme(testUri);

            bool ret = IsDomainPresentInternal(testUri);

            return ret;
        }

        /// <summary>
        /// Добавляем префикс, если нужно
        /// </summary>
        /// <param name="sourceUri">Исходный URI.</param>
        /// <returns>готовый к проверке адрес</returns>
        [CanBeNull]
        public static string AddUrlScheme(string sourceUri)
        {
            const string httpPrefix = "http:";
            const string httpSuffix = "//";

            if (!IsSchemePresent(sourceUri))
            {
                if (!string.IsNullOrEmpty(sourceUri)
                    && (sourceUri.Length < httpPrefix.Length
                         || sourceUri.IndexOf(httpPrefix, 0, httpPrefix.Length) < 0)
                    )
                {
                    if (sourceUri.Length < httpSuffix.Length 
                        || sourceUri.IndexOf(httpSuffix, 0, httpSuffix.Length) < 0)
                    {
                        sourceUri = "//" + sourceUri;
                    }

                    sourceUri = httpPrefix + sourceUri;
                }
            }
            return sourceUri;
        }

        /// <summary>
        /// Проверяем присутствует ли в заданном адресе имя домена
        /// входной адрес должен иметь "схему"
        /// </summary>
        /// <param name="urlAddress">Проверяемый URL адрес.</param>
        /// <returns>
        ///     <c>true</c> если имя домена присутствует; иначе, <c>false</c>.
        /// </returns>
        private static bool IsDomainPresentInternal(string testUri)
        {
            bool ret = IsValidUrl(testUri);
            if (ret)
            {
                Uri uri = new Uri(testUri);
                string host = uri.DnsSafeHost;

                string[] strings = host.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);

                // проверяем есть ли точка в имени носта и делит ли она имя хотябы на две части
                if (strings == null || (strings != null && strings.Length < 2))
                {
                    ret = false;
                }
                // string components = uri.GetComponents(UriComponents.Host, UriFormat.Unescaped);
            }

            return ret;
        }

        /// <summary>
        /// Determines whether [is valid URL] [the specified test URI].
        /// </summary>
        /// <param name="testUri">The test URI.</param>
        /// <returns>
        ///   <c>true</c> if [is valid URL] [the specified test URI]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValidUrl(string testUri)
        {
            bool ret = true;
            try
            {
                Uri uri = new Uri(testUri);
            }
            catch (Exception)
            {
                ret = false;
            }

            return ret;
        }

        /// <summary>
        /// Determines whether [is scheme present] [the specified URL match].
        /// </summary>
        /// <param name="urlMatch">The URL match.</param>
        /// <returns>
        ///   <c>true</c> if [is scheme present] [the specified URL match]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsSchemePresent(Match urlMatch)
        {
            return urlMatch.Groups["scheme"].Success;
        }

        /// <summary>
        /// Determines whether [is scheme present] [the specified URL].
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns>
        ///     <c>true</c> if [is scheme present] [the specified URL]; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">input is null.</exception>
        public static bool IsSchemePresent(string url)
        {
            Match match = TextFormatter.ParseUrl(url);
            return IsSchemePresent(match);
        }

        /// <summary>
        /// Gets the hostname.
        /// </summary>
        /// <param name="urlMatch">The URL match.</param>
        /// <returns></returns>
        public static string GetHostname(Match urlMatch)
        {
            return urlMatch.Groups["hostname"].Value;
        }

        /// <summary>
        /// Получить внутренний формат ссылки для соответствующего  <paramref name="resourceType"/>
        /// </summary>
        /// <param name="resourceType">Тип ресурса.</param>
        /// <param name="parameters">Параметр ссылки.</param>
        /// <returns>Внутренний формат ссылки.</returns>
        public static string FormatUri(JanusProtocolResourceType resourceType, string parameters)
        {
            return JanusProtocolDispatcher.FormatURI(resourceType, parameters);
        }
    }
}